﻿using FastORM.Definition;
using FastORM.Entity;
using FastORM.Enum;
using FastORM.Realization;
using FastUtil.Config;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Text;
using System.Threading;

namespace FastORM.Handle
{
    public class TransitionManage
    {
        private static ConcurrentDictionary<string, LocalTransaction> TransactionDic = new ConcurrentDictionary<string, LocalTransaction>();
        private static ConcurrentDictionary<string, List<string>> TransitionIDMapDic = new ConcurrentDictionary<string, List<string>>();
        public static void AddTransition(string TransitionID,string RootThreadID,  DbTransaction Transition,Action TransitionAction)
        {
            LocalTransaction LT = new LocalTransaction();
            LT.RootThreadID = RootThreadID;
            LT.TransitionID = TransitionID;
            LT.Transition = Transition;
            LT.CacheTransition = new CacheTransition();
            //执行列表增加Action
            LT.AddTransitionAction(TransitionAction);
            TransactionDic.TryAdd(TransitionID, LT);
            //增加事务根线程ID与嵌套事务相关事务ID
            TransitionIDMapDic.TryAdd(RootThreadID, new List<string>() { TransitionID });

        }
        public static void ContactTransition(string TransitionID, string RootThreadID,Action TransitionAction)
        {
            LocalTransaction LT = TransactionDic[RootThreadID];
            if (!TransactionDic.ContainsKey(LT.RootThreadID))
            {
                LT.TransitionID = TransitionID;
                //执行列表增加Action
                LT.AddTransitionAction(TransitionAction);
                TransactionDic.TryAdd(TransitionID, LT);
                //增加事务根线程ID与嵌套事务相关事务ID
                List<string> TransitionIDS = TransitionIDMapDic[LT.RootThreadID];
                TransitionIDS.Add(TransitionID);
                TransitionIDMapDic[LT.RootThreadID] = TransitionIDS;
            }
            else
            {
                ContactTransition(TransitionID, LT.RootThreadID, TransitionAction);
            }
        }
        public static string GetRootID(string TransitionID)
        {
            LocalTransaction LT = TransactionDic[TransitionID];
            if (!TransactionDic.ContainsKey(LT.RootThreadID))
            {
                return LT.RootThreadID;
            }
            else
            {
                return GetRootID(LT.RootThreadID);
            }
        }
        public static LocalTransaction GetTransition(string TransitionID)
        {
            LocalTransaction LT = null;
            TransactionDic.TryGetValue(TransitionID, out LT);
            return LT;
        }
        public static LocalTransaction GetTransitionByRootThreadID(string RootThreadID)
        {
            LocalTransaction LT = null;
            List<string> ContactTransitionIDList = TransitionIDMapDic[RootThreadID];
            if (ContactTransitionIDList.Count>0)
            {
                LT = TransactionDic[ContactTransitionIDList[0]];
            }
            return LT;
        }
        public static bool ContainsTransition(string TransitionID)
        {
            return TransactionDic.ContainsKey(TransitionID);
        }
        public static void RemoveTransition(string TransitionID)
        {
            string RootID = GetRootID(TransitionID);
            List<string> TransitionIDList = null;
            TransitionIDMapDic.TryRemove(RootID, out TransitionIDList);
            foreach (string TransitionIDItem in TransitionIDList)
            {
                LocalTransaction LT = null;
                TransactionDic.TryRemove(TransitionIDItem, out LT);
            }
        }
        public static void RemoveTransitionByRootThreadID(string RootThreadID)
        {
            List<string> TransitionIDList = null;
            TransitionIDMapDic.TryRemove(RootThreadID, out TransitionIDList);
            foreach (string TransitionIDItem in TransitionIDList)
            {
                LocalTransaction LT = null;
                TransactionDic.TryRemove(TransitionIDItem, out LT);
            }
        }


        #region 手动调用事物用法
        public static void StartTransitionByConnectString(DataBaseClass DataBaseClass, string ConnectionString)
        {
            IFastDBExecute DBExecute = SqlSessionFactory.OpenSession(DataBaseClass, ConnectionString).DBExecute;
            string RootThreadID = Thread.CurrentThread.ManagedThreadId.ToString();
            DbConnection connection = DBExecute.CreateConnection(ConnectionString);
            connection.Open();
            DbTransaction Transition = connection.BeginTransaction();
            LocalTransaction LT = new LocalTransaction();
            LT.RootThreadID = RootThreadID;
            LT.TransitionID = RootThreadID;
            LT.Transition = Transition;
            LT.CacheTransition = new CacheTransition();
            TransactionDic.TryAdd(RootThreadID, LT);
            //增加事务根线程ID与嵌套事务相关事务ID
            TransitionIDMapDic.TryAdd(RootThreadID, new List<string>() { RootThreadID });
        }

        public static void StartTransition(IsolationLevel TransitionLevel)
        {
            string ConnectionString = AppConfigUtil.Configuration["ConnectionStrings:Cloud_ConnectionString"];
            IFastDBExecute DBExecute = SqlSessionFactory.OpenSession(DataBaseClass.MySql, ConnectionString).DBExecute;
            string RootThreadID = Thread.CurrentThread.ManagedThreadId.ToString();
            DbConnection connection = DBExecute.CreateConnection(ConnectionString);
            connection.Open();
            DbTransaction Transition = connection.BeginTransaction(TransitionLevel);
            LocalTransaction LT = new LocalTransaction();
            LT.RootThreadID = RootThreadID;
            LT.TransitionID = RootThreadID;
            LT.Transition = Transition;
            LT.CacheTransition = new CacheTransition();
            TransactionDic.TryAdd(RootThreadID, LT);
            //增加事务根线程ID与嵌套事务相关事务ID
            TransitionIDMapDic.TryAdd(RootThreadID, new List<string>() { RootThreadID });
        }

        public static void DoCommit()
        {
            string RootThreadID = Thread.CurrentThread.ManagedThreadId.ToString();
            DbTransaction Transition = GetTransition(RootThreadID).Transition;
            CacheTransition CacheTransition = GetTransition(RootThreadID).CacheTransition;
            DbConnection connection = Transition.Connection;
            Transition.Commit();
            CacheTransition.Commit();
            Transition.Dispose();
            connection.Close();
            connection.Dispose();
            Transition = null;
            RemoveTransitionByRootThreadID(RootThreadID);
        }
        public static void DoRollBack()
        {
            string RootThreadID = Thread.CurrentThread.ManagedThreadId.ToString();
            DbTransaction Transition = GetTransition(RootThreadID).Transition;
            DbConnection connection = Transition.Connection;
            Transition.Rollback();
            Transition.Dispose();
            connection.Close();
            connection.Dispose();
            Transition = null;
            RemoveTransitionByRootThreadID(RootThreadID);
        }
        #endregion
    }
}
